﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;

namespace LowLevelGraphics.ColorSpaces
{
    /// <summary>
    /// I Rg By Channel
    /// </summary>
    public enum IRgByChannel
    {
        /// <summary>
        /// 
        /// </summary>
        I = 0,
        /// <summary>
        /// 
        /// </summary>
        Rg = 1,
        /// <summary>
        /// 
        /// </summary>
        By = 2
    }

    /// <summary>
    /// IRgBy Color Space this is defined by
    /// I = [L(R) + L(B) + L(G)] / 3
    /// Rg = L(R) - L(G)
    /// By = L(B) - [L(G) +L(R)] / 2
    /// where L is a logarithmic function. 
    /// </summary>
    [DebuggerDisplay("I: {m_I}, Rg: {m_Rg}, By: {m_By}, Hue: {m_Hue}")]
    public class IRgBy : AbstractColorSpace
    {
        protected double m_I = 0.0f;
        protected double m_Rg = 0.0f;
        protected double m_By = 0.0f;
        protected double m_Hue = 0.0f;

        /// <summary>
        /// primary constructor
        /// </summary>
        /// <param name="_color"></param>
        public IRgBy(Color _color)
            : base(_color)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IRgBy"/> class.
        /// </summary>
        /// <param name="_I">The _ I.</param>
        /// <param name="_Rg">The _ rg.</param>
        /// <param name="_By">The _ by.</param>
        /// <param name="_hue">The _hue.</param>
        public IRgBy(double _I, double _Rg, double _By, double _hue)
        {
            this.m_I = _I;
            this.m_Rg = _Rg;
            this.m_By = _By;
            this.m_Hue = _hue;
        }

        /// <summary>
        /// Used by clone to create a deep copy
        /// </summary>
        /// <param name="_irgby"></param>
        internal IRgBy(IRgBy _irgby)
        {
            this.m_Color = _irgby.m_Color;
            this.m_I = _irgby.m_I;
            this.m_Rg = _irgby.m_Rg;
            this.m_By = _irgby.m_By;
            this.m_Hue = _irgby.m_Hue;
        }

        /// <summary>
        /// enables you to cast rgb color into this color space
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static explicit operator IRgBy(Color _color)
        {
            return new IRgBy(_color);
        }

        /// <summary>
        /// Gets or sets I
        /// </summary>
        public double I
        {
            get { return m_I; }
            set { m_I = value; }
        }

        /// <summary>
        /// Gets or sets Rg
        /// </summary>
        public double Rg
        {
            get { return m_Rg; }
            set { m_Rg = value; }
        }

        /// <summary>
        /// Gets or sets By
        /// </summary>
        public double By
        {
            get { return m_By; }
            set { m_By = value; }
        }

        /// <summary>
        /// Gets hue
        /// </summary>
        public double Hue
        {
            get { return m_Hue; }
        }

        /// <summary>
        /// Normalize
        /// </summary>
        /// <returns></returns>
        public override AbstractColorSpace Normalize()
        {
            return base.Normalize();
        }

        /// <summary>
        /// Convert to this color space
        /// </summary>
        protected override void CalcValues()
        {
            m_I = (Math.Log(m_Color.R) + Math.Log(m_Color.B) + Math.Log(m_Color.G)) / 3;
            m_Rg = Math.Log(m_Color.R) - Math.Log(m_Color.G);
            m_By = Math.Log(m_Color.B) - (Math.Log(m_Color.G) + Math.Log(m_Color.R)) / 2;
            m_Hue = Math.Atan2(m_Rg, m_By) * (180 / Math.PI);
        }

        /// <summary>
        /// Convert back to RGB color space
        /// </summary>
        /// <returns></returns>
        public override Color ToColor()
        {
            int r = (int)(Math.Exp(m_I * 3 - Math.Log(m_Color.B) - Math.Log(m_Color.G)));
            int g = (int)Math.Exp(m_Rg - Math.Log(m_Color.R));
            int b = (int)Math.Exp((m_By - (int)(Math.Log(m_Color.G) - Math.Log(m_Color.R))) * 2);
            return Color.FromArgb(0, 0, 0);
        }

        /// <summary>
        /// Gets the values.
        /// </summary>
        /// <returns></returns>
        public override object[] GetValues()
        {
            return new object[] { m_I, m_Rg, m_By };
        }

        /// <summary>
        /// Sets the values.
        /// </summary>
        /// <param name="_aObject">The _a object.</param>
        public override void SetValues(object[] _aObject)
        {
            this.m_I = (double)_aObject[0];
            this.m_Rg = (double)_aObject[1];
            this.m_By = (double)_aObject[2];
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("Color: I: {0}, Rg: {1}, By: {2}", m_I, m_Rg, m_By);
        }

        /// <summary>
        /// Used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new IRgBy(this);
        }
    }
}
